package top.yinjinbiao.arcface.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.arcsoft.face.FaceInfo;
import com.arcsoft.face.toolkit.ImageFactory;
import com.arcsoft.face.toolkit.ImageInfo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import top.yinjinbiao.arcface.common.exception.CustomException;
import top.yinjinbiao.arcface.common.exception.ErrorCodeEnum;
import top.yinjinbiao.arcface.common.rpc.ResponseResult;
import top.yinjinbiao.arcface.common.util.Base64Util;
import top.yinjinbiao.arcface.domain.dto.FacePersonDTO;
import top.yinjinbiao.arcface.domain.dto.FaceRecognitionResDTO;
import top.yinjinbiao.arcface.domain.entity.FacePerson;
import top.yinjinbiao.arcface.domain.dto.UserCompareInfo;
import top.yinjinbiao.arcface.domain.excel.FacePersonExcel;
import top.yinjinbiao.arcface.domain.form.FacePersonForm;
import top.yinjinbiao.arcface.domain.query.FacePersonQuery;
import top.yinjinbiao.arcface.service.FaceEngineService;
import top.yinjinbiao.arcface.service.FacePersonService;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description 终端人脸识别接口集合
 * @Author yin.jinbiao kaige
 * @Date 2021/9/26 15:50
 * @Version 1.1
 */
@RestController
@RequestMapping(value = "faceperson")
@Slf4j
public class ArcfaceController {

    @Autowired
    private FaceEngineService faceEngineService;

    @Autowired
    private FacePersonService facePersonService;

    /**
     * 人脸库删除
     * @param id
     * @return
     */
    @PostMapping("del")
    public ResponseResult del(Long id){
        facePersonService.delete(id);
        return ResponseResult.ok();
    }

    /**
     * 添加信息到人脸库
     * @param form
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("add")
    public ResponseResult addFacePerson(@Validated FacePersonForm form, MultipartFile file) throws IOException {
        // 提取人脸特征存储
        ImageInfo rgbData = ImageFactory.getRGBData(file.getBytes());
        List<FaceInfo> faceInfoList = faceEngineService.detectFaces(rgbData);
        if (CollectionUtil.isEmpty(faceInfoList)) {
            throw new CustomException(ErrorCodeEnum.PARAM_ILLEGAL,"not recognize face.","没有检测到人脸信息。");
        }
        FacePerson facePerson = new FacePerson();
        byte[] feature = faceEngineService.extractFaceFeature(rgbData, faceInfoList.get(0));
        facePerson.setName(form.getName());
        facePerson.setFeature(feature);
        facePersonService.add(facePerson);
        // TODO 同步上传图片到文件库，用于展示原图片。（自己另外实现文件上传服务）
        return ResponseResult.ok();

    }

    /**
     * 人脸库分页
     * @param page
     * @param query
     * @return
     */
    @GetMapping("page")
    public ResponseResult page(Page<FacePersonDTO> page, FacePersonQuery query){
        return ResponseResult.ok(facePersonService.page(page,query));
    }

    /**
     * 人脸识别
     * @param image
     * @return
     */
    @PostMapping(value = "facerecognition")
    public ResponseResult<List<FaceRecognitionResDTO>> faceRecognition(String image)  {
        // 1. 读取人脸库所有信息
        List list = facePersonService.list();

        // 2. 接收传递的base64数据，转字节数组
        byte[] rgbData = Base64Util.base64ToBytes(image);
        // 3. 从字节数组中解析出图片信息
        ImageInfo imageInfo = ImageFactory.getRGBData(rgbData);

        // 4. 从图片信息中分离出人脸信息，一个图片中可能有多张人脸
        List<FaceInfo> faceInfoList = faceEngineService.detectFaces(imageInfo);

        // 5. 遍历图片中所有的人脸，分别提取它们的脸部特征信息，与人脸库比对
        List<FaceRecognitionResDTO> faceRecognitionResDTOList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(faceInfoList)) {
            for (FaceInfo faceInfo : faceInfoList) {
                FaceRecognitionResDTO faceRecognitionResDTO = new FaceRecognitionResDTO();
                faceRecognitionResDTO.setRect(faceInfo.getRect());
                //特征提取
                byte[] feature = faceEngineService.extractFaceFeature(imageInfo, faceInfo);
                if (feature != null) {
                    List<UserCompareInfo> userCompareInfos = faceEngineService.faceRecognition(feature, list, 0.0f);
                    if (CollectionUtil.isNotEmpty(userCompareInfos)) {
                        faceRecognitionResDTO.setName(userCompareInfos.get(0).getName());
                        faceRecognitionResDTO.setSimilar(userCompareInfos.get(0).getSimilar());
                    }
                }
                faceRecognitionResDTOList.add(faceRecognitionResDTO);
            }
        }
        return ResponseResult.ok(faceRecognitionResDTOList);

    }


    @PostMapping("importFaceBase")
    public ResponseResult importFaceBase(MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(), FacePersonExcel.class,new PageReadListener<FacePersonExcel>(dataList ->{
            for (FacePersonExcel model:dataList) {
                log.info("读取到一条数据{}", JSONUtil.toJsonStr(model));
            }
        })).sheet().doRead();
        return ResponseResult.ok();
    }

}
